package com.qf.authserver.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableAuthorizationServer  //表示该服务是一个授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private DataSource dataSource;

    @Bean
    public ClientDetailsService jdbcClientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

    //生成授权码，并保存在数据库中
    @Bean
    public JdbcAuthorizationCodeServices jdbcAuthorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    //生成access_token然后保存数据库中
    @Bean
    public JdbcTokenStore jdbcTokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(jdbcClientDetailsService());
        // 演示
        /**
        clients.inMemory()  //
                .withClient("a")   //配置client_id
                .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga")  //密码
                .authorizedGrantTypes("authorization_code") //
                .redirectUris("http://localhost:7070/login")
                // scope在资源服务器上使用，如果用户要访问的资源允许该scope，才可以访问,  使用的方式是
                // antMatchers("/userinfo").access("#oauth2.hasAnyScope('userinfo')")
                .scopes("userinfo")
                .and()
                .withClient("b")   //配置client_id
                .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga")  //密码
                .authorizedGrantTypes("authorization_code") //
                .redirectUris("http://localhost:7070/login")
                .scopes("user")
                .and()
                .withClient("resource-server")
                .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga");
         */
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 在获取access_token的时候，允许的请求方式
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        // 授权码配置
        endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices())  // 授权码的服务配置，需要使用数据
                  .tokenStore(jdbcTokenStore());  // 配置access_token相关的信息。
        // 生成一个什么样的token
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(false);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        // token的过期时间为1天
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(1));
        endpoints.tokenServices(tokenServices);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
        // 对资源服务器的secret使用哪个密码验证器
        security.passwordEncoder(passwordEncoder);
        // 验证信息通过了才让其校验access_token
        security.checkTokenAccess("isAuthenticated()");
    }
}
